﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Windows;
using System.Windows.Browser.Net;
using System.Windows.Documents;
using System.Windows.Media;
using System.Xml;

namespace AgLux
{
    /// <summary>
    /// Provides function to create a Course object by parsing data from XML.
    /// </summary>

    public static class Parser
    {
        /// <summary>
        /// Parses course data from XML.
        /// </summary>

        /// <returns>
        /// A created Course object.
        /// </returns>

        public static Course ParseCourse()
        {
            string title = "Course";
            string description = "Description";
            List<Section> sections = new List<Section>();

            HttpWebRequest request = new BrowserHttpWebRequest(new Uri("Course/course.xml", UriKind.Relative));
            HttpWebResponse response = request.GetResponse();
            XmlReader reader = XmlReader.Create(GetReader(response.GetResponseStream()));
            
            while (reader.Read())
            {
                if (reader.IsStartElement() && reader.Depth == 0 && reader.LocalName == "course")
                {
                    while (reader.MoveToNextAttribute())
                    {
                        if (reader.Name == "title")
                        {
                            title = reader.Value;
                        }

                        else if (reader.Name == "description")
                        {
                            description = reader.Value;
                        }
                    }
                }

                if (reader.IsStartElement() && reader.Depth == 1 && reader.LocalName == "section")
                {
                    string headline = "Section";

                    while (reader.MoveToNextAttribute())
                    {
                        if (reader.Name == "headline")
                        {
                            headline = reader.Value;
                        }
                    }

                    reader.MoveToElement();
                    sections.Add(ParseSection(headline, reader.ReadSubtree()));
                }
            }

            response.Close();
            return new Course(title, description, new Structure(sections));
        }

        /// <summary>
        /// Parses section data from XML.
        /// </summary>

        /// <param name="headline">
        /// The section headline.
        /// </param>

        /// <param name="reader">
        /// The XML reader.
        /// </param>

        /// <returns>
        /// A created Section object.
        /// </returns>

        private static Section ParseSection(string headline, XmlReader reader)
        {
            List<Component> components = new List<Component>();
            List<Section> subSections = new List<Section>();

            while (reader.Read())
            {
                if (reader.IsStartElement() && reader.Depth == 1)
                {
                    if (reader.LocalName == "text")
                    {
                        string background = "#00FFFFFF";

                        while (reader.MoveToNextAttribute())
                        {
                            if (reader.Name == "background")
                            {
                                background = reader.Value;
                            }
                        }

                        reader.MoveToElement();
                        components.Add(ParseText(background, reader.ReadSubtree()));
                    }

                    else if (reader.LocalName == "link")
                    {
                        string text = null;

                        while (reader.MoveToNextAttribute())
                        {
                            if (reader.Name == "text")
                            {
                                text = reader.Value;
                            }
                        }

                        reader.MoveToElement();
                        components.Add(new Link(reader.ReadElementContentAsString(), text));
                    }

                    else if (reader.LocalName == "picture")
                    {
                        string caption = null;
                        Filling filling = Filling.half;

                        while (reader.MoveToNextAttribute())
                        {
                            if (reader.Name == "caption")
                            {
                                caption = reader.Value;
                            }

                            else if (reader.Name == "filling" && reader.Value == "full")
                            {
                                filling = Filling.full;
                            }

                            else if (reader.Name == "filling" && reader.Value == "oneFourth")
                            {
                                filling = Filling.oneFourth;
                            }

                            else if (reader.Name == "filling" && reader.Value == "threeFourth")
                            {
                                filling = Filling.threeFourth;
                            }
                        }

                        reader.MoveToElement();
                        components.Add(new Picture("Course/" + reader.ReadElementContentAsString(), caption, filling));
                    }

                    else if (reader.LocalName == "audio")
                    {
                        string caption = null;
                        string transcript = null;

                        while (reader.MoveToNextAttribute())
                        {
                            if (reader.Name == "caption")
                            {
                                caption = reader.Value;
                            }

                            else if (reader.Name == "transcript")
                            {
                                transcript = "Course/" + reader.Value;
                            }
                        }

                        reader.MoveToElement();
                        components.Add(new Audio("Course/" + reader.ReadElementContentAsString(), caption, transcript));
                    }

                    else if (reader.LocalName == "video")
                    {
                        string caption = null;
                        string transcript = null;
                        Filling filling = Filling.half;

                        while (reader.MoveToNextAttribute())
                        {
                            if (reader.Name == "caption")
                            {
                                caption = reader.Value;
                            }

                            else if (reader.Name == "transcript")
                            {
                                transcript = "Course/" + reader.Value;
                            }

                            else if (reader.Name == "filling" && reader.Value == "full")
                            {
                                filling = Filling.full;
                            }

                            else if (reader.Name == "filling" && reader.Value == "oneFourth")
                            {
                                filling = Filling.oneFourth;
                            }

                            else if (reader.Name == "filling" && reader.Value == "threeFourth")
                            {
                                filling = Filling.threeFourth;
                            }
                        }

                        reader.MoveToElement();
                        components.Add(new Video("Course/" + reader.ReadElementContentAsString(), caption, transcript, filling));
                    }

                    else if (reader.LocalName == "animation")
                    {
                        string caption = null;
                        bool autostarting = true;

                        while (reader.MoveToNextAttribute())
                        {
                            if (reader.Name == "caption")
                            {
                                caption = reader.Value;
                            }

                            else if (reader.Name == "autostarting" && reader.Value == "no")
                            {
                                autostarting = false;
                            }
                        }

                        reader.MoveToElement();
                        components.Add(new Animation("Course/" + reader.ReadElementContentAsString(), caption, autostarting));
                    }

                    else if (reader.LocalName == "task")
                    {
                        components.Add(ParseTask(reader.ReadSubtree()));
                    }

                    else if (reader.LocalName == "section")
                    {
                        string subHeadline = "Section";

                        while (reader.MoveToNextAttribute())
                        {
                            if (reader.Name == "headline")
                            {
                                subHeadline = reader.Value;
                            }
                        }

                        reader.MoveToElement();
                        subSections.Add(ParseSection(subHeadline, reader.ReadSubtree()));
                    }
                }
            }

            return new Section(headline, components, subSections);
        }

        /// <summary>
        /// Parses text data from XML.
        /// </summary>

        /// <param name="background">
        /// The text background.
        /// </param>

        /// <param name="reader">
        /// The XML reader.
        /// </param>

        /// <returns>
        /// A created Text object.
        /// </returns>

        private static Text ParseText(string background, XmlReader reader)
        {
            List<Inline> content = new List<Inline>();

            while (reader.Read())
            {
                if (reader.IsStartElement() && reader.Depth == 1)
                {
                    if (reader.LocalName == "part")
                    {
                        Run part = new Run();
                        part.FontFamily = "Arial";

                        while (reader.MoveToNextAttribute())
                        {
                            if (reader.Name == "font")
                            {
                                part.FontFamily = reader.Value;
                            }

                            else if (reader.Name == "size")
                            {
                                part.FontSize = Convert.ToInt32(reader.Value);
                            }

                            else if (reader.Name == "color")
                            {
                                part.SetValue(Run.ForegroundProperty, reader.Value);
                            }

                            else if (reader.Name == "bold" && reader.Value == "yes")
                            {
                                part.FontWeight = FontWeights.Bold;
                            }

                            else if (reader.Name == "italic" && reader.Value == "yes")
                            {
                                part.FontStyle = FontStyles.Italic;
                            }

                            else if (reader.Name == "underlined" && reader.Value == "yes")
                            {
                                part.TextDecorations = TextDecorations.Underline;
                            }
                        }

                        reader.MoveToElement();
                        part.Text = reader.ReadElementContentAsString();
                        content.Add(part);
                    }

                    else if (reader.LocalName == "break")
                    {
                        content.Add(new LineBreak());
                    }
                }
            }

            return new Text(content, background);
        }

        /// <summary>
        /// Parses task data from XML.
        /// </summary>

        /// <param name="reader">
        /// The XML reader.
        /// </param>

        /// <returns>
        /// A created Task object.
        /// </returns>

        private static Task ParseTask(XmlReader reader)
        {
            List<Question> questions = new List<Question>();

            while (reader.Read())
            {
                if (reader.IsStartElement() && reader.Depth == 1)
                {
                    if (reader.LocalName == "question")
                    {
                        string text = "Question";

                        while (reader.MoveToNextAttribute())
                        {
                            if (reader.Name == "text")
                            {
                                text = reader.Value;
                            }
                        }

                        reader.MoveToElement();
                        questions.Add(ParseQuestion(text, reader.ReadSubtree()));
                    }
                }
            }

            return new Task(questions);
        }

        /// <summary>
        /// Parses question data from XML.
        /// </summary>

        /// <param name="text">
        /// The question text.
        /// </param>

        /// <param name="reader">
        /// The XML reader.
        /// </param>

        /// <returns>
        /// A created Question object.
        /// </returns>

        private static Question ParseQuestion(string text, XmlReader reader)
        {
            List<Answer> answers = new List<Answer>();

            while (reader.Read())
            {
                if (reader.IsStartElement() && reader.Depth == 1)
                {
                    if (reader.LocalName == "answer")
                    {
                        bool correct = true;

                        while (reader.MoveToNextAttribute())
                        {
                            if (reader.Name == "correct" && reader.Value == "no")
                            {
                                correct = false;
                            }
                        }

                        reader.MoveToElement();
                        answers.Add(new Answer(reader.ReadElementContentAsString(), correct));
                    }
                }
            }

            return new Question(text, answers);
        }

        /// <summary>
        /// Gets a StreamReader object that is FireFox safe.
        /// </summary>

        /// <param name="stream">
        /// The stream to be read.
        /// </param>

        /// <returns>
        /// A StreamReader object.
        /// </returns>

        private static StreamReader GetReader(Stream stream)
        {
            StreamReader reader = new StreamReader(stream);

            while (reader.Peek() != Convert.ToInt32('<'))
            {
                reader.Read();
            }

            return reader;

        }
    }
}
